package com.itx.gatewayx.filter;

import com.alibaba.fastjson2.JSON;
import com.itx.gatewayx.common.R;
import com.itx.gatewayx.utils.JwtUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;

/**
 * 自定义JWT认证过滤器
 *
 * @author itx
 */
@Slf4j
@Component
@Order(-1) // 确保在其他过滤器之前执行
@RequiredArgsConstructor
public class CustomAuthFilter implements WebFilter {
    
    private final JwtUtils jwtUtils;
    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    
    // 白名单路径，无需认证
    private final List<String> whiteList = Arrays.asList(
        "/api/user/login",
        "/api/user/register",
        "/api/user/check-username",
        "/api/user/check-email",
        "/api/news/**",
        "/api/news/categories",
        "/api/news/list",
        "/api/news/detail/**",
        "/api/news/hot",
        "/api/news/search",
        "/api/comments/**",
        "/api/comments/list/**",
        "/api/auth/**",
        "/favicon.ico",
        "/doc.html",
        "/webjars/**",
        "/swagger-resources/**",
        "/v3/api-docs/**"
    );
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String path = request.getPath().value();
        
        // 记录请求日志
        log.debug("请求路径: {}, 方法: {}", path, request.getMethod());
        
        // 对OPTIONS请求放行
        if (request.getMethod().matches("OPTIONS")) {
            return chain.filter(exchange);
        }
        
        // 白名单路径直接放行
        if (isWhitePath(path)) {
            return chain.filter(exchange);
        }
        
        // 获取token
        String token = getTokenFromRequest(exchange);
        
        // 验证token
        if (!StringUtils.hasText(token)) {
            return responseUnauthorized(response, "未提供认证令牌");
        }
        
        // 验证token有效性
        try {
            if (!jwtUtils.validateToken(token)) {
                return responseUnauthorized(response, "认证令牌已过期或无效");
            }
            
            // 获取用户信息
            Long userId = jwtUtils.getUserIdFromToken(token);
            
            // 设置用户ID到ThreadLocal
            com.itx.gatewayx.utils.UserUtils.setCurrentUserId(userId);
            
            // 创建增强的请求，添加用户ID到请求头
            ServerHttpRequest enhancedRequest = request.mutate()
                    .header("X-User-ID", String.valueOf(userId))
                    .build();
            
            // 使用增强的请求继续过滤器链，并在完成后清除ThreadLocal
            return chain.filter(exchange.mutate().request(enhancedRequest).build())
                    .doFinally(signalType -> {
                        // 请求结束后清除ThreadLocal
                        com.itx.gatewayx.utils.UserUtils.clearCurrentUserId();
                    });
        } catch (Exception e) {
            log.error("认证失败", e);
            return responseUnauthorized(response, "认证处理失败");
        }
    }
    
    /**
     * 检查是否是白名单路径
     */
    private boolean isWhitePath(String path) {
        return whiteList.stream().anyMatch(pattern -> pathMatcher.match(pattern, path));
    }
    
    /**
     * 从请求中获取token
     */
    private String getTokenFromRequest(ServerWebExchange exchange) {
        String bearerToken = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
    
    /**
     * 响应未授权信息
     */
    private Mono<Void> responseUnauthorized(ServerHttpResponse response, String message) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        
        R<Object> result = R.fail(401, message);
        byte[] bytes = JSON.toJSONString(result).getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = response.bufferFactory().wrap(bytes);
        return response.writeWith(Mono.just(buffer));
    }
} 